package com.lingjtx.common.thread.config;


import com.alibaba.fastjson2.JSON;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import com.lingjtx.common.core.util.StringUtil;
import com.lingjtx.common.thread.commom.ObjectPoolRefreshEven;
import com.lingjtx.common.thread.commom.ThreadPoolRefreshEvent;
import com.lingjtx.common.thread.core.PoolNameConst;
import com.lingjtx.common.thread.core.ThreadPoolManager;
import jakarta.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.yaml.snakeyaml.Yaml;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.concurrent.Executor;

@Configuration
@ConfigurationProperties(prefix = "thread-pools")
public class ExecutorConfig implements Ordered {

    private static final Logger log = LoggerFactory.getLogger(ExecutorConfig.class);

    private Map<String, PoolConfig> executors = new HashMap<>();
    private Map<String, ObjectPoolConfig> templates = new HashMap<>();

    private final ThreadPoolManager threadPoolManager;
    private final ApplicationEventPublisher publisher;

    @Value("${spring.cloud.nacos.discovery.server-addr}")
    private String nacosServerAddr;

    public ExecutorConfig(ThreadPoolManager threadPoolManager, ApplicationEventPublisher publisher) {
        this.threadPoolManager = threadPoolManager;
        this.publisher = publisher;
    }

    @PostConstruct
    public void init() {
        // 在构造之后注册 Nacos 配置监听器
        registerNacosConfigListener();
    }

    public Map<String, PoolConfig> getExecutors() {
        return executors;
    }

    public void setExecutors(Map<String, PoolConfig> executors) {
        this.executors = executors;
    }

    public Map<String, ObjectPoolConfig> getTemplates() {
        return templates;
    }

    public void setTemplates(Map<String, ObjectPoolConfig> templates) {
        this.templates = templates;
    }

    private void registerNacosConfigListener() {
        try {
            // 创建 Nacos ConfigService
            Properties properties = new Properties();
            properties.put("serverAddr", nacosServerAddr);
            properties.put("namespace", "");
            ConfigService configService = NacosFactory.createConfigService(properties);

            // 注册监听器
            configService.addListener("thread-pools-config.yml", "DEFAULT_GROUP", new Listener() {
                @Override
                public void receiveConfigInfo(String configInfo) {
                    // 配置更新回调
                    onConfigChange(configInfo);
                }

                @Override
                public Executor getExecutor() {
                    return threadPoolManager.getOrCreate(PoolNameConst.POOL_DEFAULT); // 默认执行器，使用默认线程池
                }
            });
        } catch (NacosException e) {
            log.error("Error while registering Nacos config listener.", e);
        }
    }

    private String lastConfig = "";

    // 配置更新处理
    private void onConfigChange(String newConfig) {
        if (StringUtil.isEmpty(newConfig)) {
            log.warn("接收到空配置内容，跳过处理");
            return;
        }
        if (Objects.equals(newConfig, lastConfig)) {
            log.info("配置未发生变化，跳过刷新");
            return;
        }
        lastConfig = newConfig;
        log.info("Nacos configuration updated: {}", newConfig);
        try {
            Yaml yaml = new Yaml();
            Map<String, Object> yamlMap = yaml.load(newConfig);
            Object node = yamlMap.get("thread-pools");
            if (node instanceof Map<?, ?> threadPoolsMap) {
                if (threadPoolsMap.containsKey("executors")) {
                    Object executorMapRaw = threadPoolsMap.get("executors");
                    Map<String, PoolConfig> updatedExecutors = convertToMap(executorMapRaw, PoolConfig.class);
                    this.executors = updatedExecutors;

                    // 刷新线程池实例
                    updatedExecutors.forEach((name, config) -> {
                        publisher.publishEvent(new ThreadPoolRefreshEvent(this, name, config));
                    });
                }

                if (threadPoolsMap.containsKey("templates")) {
                    Object templateMapRaw = threadPoolsMap.get("templates");
                    Map<String, ObjectPoolConfig> updatedTemplates = convertToMap(templateMapRaw, ObjectPoolConfig.class);
                    this.templates = updatedTemplates;

                    // 刷新对象池（池化对象）
                    updatedTemplates.forEach((name, config) -> {
                        publisher.publishEvent(new ObjectPoolRefreshEven(this, name, config));
                    });
                }
            }
        } catch (Exception e) {
            log.error("解析 Nacos 配置失败，内容格式不正确：{}", newConfig, e);
        }
    }

    @Override
    public int getOrder() {
        return 3;
    }

    private <V> Map<String, V> convertToMap(Object mapObj, Class<V> vClass) {
        Map<String, V> result = new HashMap<>();
        if (mapObj instanceof Map<?, ?> rawMap) {
            rawMap.forEach((k, v) -> {
                try {
                    // 将对象 v 转换为 JSON 字符串
                    String json = JSON.toJSONString(v);
                    // 将 JSON 字符串转换为 PoolConfig 对象
                    V config = JSON.parseObject(json, vClass);
                    result.put(k.toString(), config);
                } catch (Exception e) {
                    log.warn("转换线程池配置失败：{}", k, e);
                }
            });
        }
        return result;
    }

    public static class PoolConfig {
        private int corePoolSize = Runtime.getRuntime().availableProcessors();
        private int maxPoolSize = corePoolSize * 2;
        private int queueCapacity = 100;
        private int keepAliveSeconds = 60;
        private String rejectedPolicy = "CallerRunsPolicy";

        public int getCorePoolSize() {
            return corePoolSize;
        }

        public void setCorePoolSize(int corePoolSize) {
            this.corePoolSize = corePoolSize;
        }

        public int getMaxPoolSize() {
            return maxPoolSize;
        }

        public void setMaxPoolSize(int maxPoolSize) {
            this.maxPoolSize = maxPoolSize;
        }

        public int getQueueCapacity() {
            return queueCapacity;
        }

        public void setQueueCapacity(int queueCapacity) {
            this.queueCapacity = queueCapacity;
        }

        public int getKeepAliveSeconds() {
            return keepAliveSeconds;
        }

        public void setKeepAliveSeconds(int keepAliveSeconds) {
            this.keepAliveSeconds = keepAliveSeconds;
        }

        public String getRejectedPolicy() {
            return rejectedPolicy;
        }

        public void setRejectedPolicy(String rejectedPolicy) {
            this.rejectedPolicy = rejectedPolicy;
        }
    }

    public static class ObjectPoolConfig {
        private long maxWaitMillis = 5000; // 获取连接时的最大等待时间（毫秒）
        private long cleanupIntervalMillis = 60000; // 清理周期，单位：毫秒
        private long expansionThresholdMillis = 3000; // 当等待时间超过该值时，触发池扩展
        private long idleTimeoutMillis = 60000; // 空闲连接的最大超时，超过该时间的连接将被销毁
        private int maxSize = 10; // 连接池的最大值
        private int initialSize = 5; // 连接池的初始化值

        public long getMaxWaitMillis() {
            return maxWaitMillis;
        }

        public void setMaxWaitMillis(long maxWaitMillis) {
            this.maxWaitMillis = maxWaitMillis;
        }

        public long getCleanupIntervalMillis() {
            return cleanupIntervalMillis;
        }

        public void setCleanupIntervalMillis(long cleanupIntervalMillis) {
            this.cleanupIntervalMillis = cleanupIntervalMillis;
        }

        public long getExpansionThresholdMillis() {
            return expansionThresholdMillis;
        }

        public void setExpansionThresholdMillis(long expansionThresholdMillis) {
            this.expansionThresholdMillis = expansionThresholdMillis;
        }

        public long getIdleTimeoutMillis() {
            return idleTimeoutMillis;
        }

        public void setIdleTimeoutMillis(long idleTimeoutMillis) {
            this.idleTimeoutMillis = idleTimeoutMillis;
        }

        public int getMaxSize() {
            return maxSize;
        }

        public void setMaxSize(int maxSize) {
            this.maxSize = maxSize;
        }

        public int getInitialSize() {
            return initialSize;
        }

        public void setInitialSize(int initialSize) {
            this.initialSize = initialSize;
        }
    }
}
